package com.zysstudy.web.lock.aspect;


import com.zysstudy.web.lock.keygenerator.RequestKeyGenerator;
import com.zysstudy.web.lock.annotation.RequestLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;


/**
 * @author zhaoyoushui
 * @date 2025/8/1 11:25
 * @Description
 * @Copyright 南京优通信息科技股份有限公司
 */
@Aspect
@Configuration
public class RequestLockMethodAspect {


    private final StringRedisTemplate stringRedisTemplate;
    private final RequestKeyGenerator requestKeyGenerator;


    @Autowired
    public RequestLockMethodAspect(StringRedisTemplate stringRedisTemplate, RequestKeyGenerator requestKeyGenerator) {
        this.requestKeyGenerator = requestKeyGenerator;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Around("execution(public * * (..)) && @annotation(com.zysstudy.web.lock.annotation.RequestLock)")
    public Object interceptor(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        RequestLock requestLock = method.getAnnotation(RequestLock.class);
        if (StringUtils.isEmpty(requestLock.prefix())) {
//            throw new RuntimeException("重复提交前缀不能为空");
            return "重复提交前缀不能为空";
        }
        //获取自定义key
        final String lockKey = requestKeyGenerator.getLockKey(joinPoint);
        final Boolean success = stringRedisTemplate.execute(
                (RedisCallback<Boolean>) connection -> connection.set(lockKey.getBytes(), new byte[0], Expiration.from(requestLock.expire(), requestLock.timeUnit())
                        , RedisStringCommands.SetOption.SET_IF_ABSENT));
        if (!success) {
//            throw new RuntimeException("您的操作太快了,请稍后重试");
            return "您的操作太快了,请稍后重试";
        }
        try {
            return joinPoint.proceed();
        } catch (Throwable throwable) {
//            throw new RuntimeException("系统异常");
            return "系统异常";
        }
    }


}
